package com.ikingtech.platform.business.message.controller;

import com.ikingtech.framework.sdk.context.exception.FrameworkException;
import com.ikingtech.framework.sdk.context.security.Me;
import com.ikingtech.framework.sdk.core.response.R;
import com.ikingtech.framework.sdk.enums.message.MessageChannelStatusEnum;
import com.ikingtech.framework.sdk.enums.message.MessageSendChannelEnum;
import com.ikingtech.framework.sdk.message.api.MessageTemplateApi;
import com.ikingtech.framework.sdk.message.model.*;
import com.ikingtech.framework.sdk.message.model.rpc.MessageBusinessTypeQueryParamDTO;
import com.ikingtech.framework.sdk.message.model.rpc.MessageTemplateBeanDefinitionReportParam;
import com.ikingtech.framework.sdk.utils.Tools;
import com.ikingtech.framework.sdk.web.annotation.ApiController;
import com.ikingtech.framework.sdk.web.annotation.PostRequest;
import com.ikingtech.platform.business.message.entity.MessageChannelDefinitionDO;
import com.ikingtech.platform.business.message.entity.MessageParamDefinitionDO;
import com.ikingtech.platform.business.message.entity.MessageRedirectDefinitionDO;
import com.ikingtech.platform.business.message.entity.MessageTemplateDO;
import com.ikingtech.platform.business.message.exception.MessageExceptionInfo;
import com.ikingtech.platform.business.message.service.MessageChannelDefinitionService;
import com.ikingtech.platform.business.message.service.MessageParamDefinitionService;
import com.ikingtech.platform.business.message.service.MessageRedirectDefinitionService;
import com.ikingtech.platform.business.message.service.MessageTemplateService;
import io.swagger.v3.oas.annotations.Parameter;
import lombok.RequiredArgsConstructor;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestBody;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * 消息中心-模板管理
 *
 * @author tie yan
 */
@RequiredArgsConstructor
@ApiController(value = "/message/template", name = "消息中心-模板管理", description = "消息中心-模板管理")
public class MessageTemplateController implements MessageTemplateApi {

    private final MessageTemplateService service;

    private final MessageChannelDefinitionService channelDefinitionService;

    private final MessageParamDefinitionService paramDefinitionService;

    private final MessageRedirectDefinitionService redirectDefinitionService;

    /**
     * 删除模板
     *
     * @param id 编号
     * @return 删除结果
     */
    @PostRequest(order = 1, value = "/delete", summary = "删除模板", description = "删除模板")
    public R<Object> delete(@Parameter(name = "id", description = "编号")
                            @RequestBody String id) {
        // 根据编号获取模板实体
        MessageTemplateDO entity = this.service.getById(id);
        if (null == entity) {
            return R.ok();
        }
        // 如果模板不是可配置的，则抛出异常
        if (!Boolean.TRUE.equals(entity.getConfigurable())) {
            throw new FrameworkException("不允许删除内置模板。");
        }
        // 将模板的配置状态设置为未配置
        entity.setConfigured(false);
        // 更新模板实体
        this.service.updateById(entity);
        // 根据模板编号删除渠道定义
        this.channelDefinitionService.removeByTemplateId(id);
        // 根据模板编号删除参数定义
        this.paramDefinitionService.removeNonPreDefinitionByTemplateId(id);
        // 根据模板编号删除重定向定义
        this.redirectDefinitionService.removeByTemplateId(id);
        return R.ok();
    }

    /**
     * 更新消息模板
     *
     * @param template 消息模板基本信息
     * @return 更新结果
     */
    @PostRequest(order = 2, value = "/update", summary = "更新消息模板", description = "更新消息模板")
    public R<Object> update(@RequestBody MessageTemplateBasicDTO template) {
        // 检查消息模板是否存在
        if (!this.service.exist(template.getId())) {
            throw new FrameworkException(MessageExceptionInfo.MESSAGE_TEMPLATE_NOT_FOUND);
        }
        // 更新消息模板
        this.service.updateById(Tools.Bean.copy(template, MessageTemplateDO.class));
        return R.ok();
    }

    /**
     * 分页查询消息模板
     *
     * @param queryParam 查询参数
     * @return 消息模板列表
     */
    @PostRequest(order = 3, value = "/list/page", summary = "分页查询消息模板", description = "分页查询消息模板")
    public R<List<MessageTemplateBasicDTO>> page(@Parameter(name = "queryParam", description = "查询参数")
                                                 @RequestBody MessageTemplateQueryParamDTO queryParam) {
        List<String> templateIds = new ArrayList<>();
        if (Tools.Str.isNotBlank(queryParam.getChannel())) {
            // 根据渠道类型获取消息模板ID列表
            templateIds.addAll(this.channelDefinitionService.listTemplateIdByChannelType(queryParam.getChannel()));
            if (Tools.Coll.isBlank(templateIds)) {
                return R.ok(new ArrayList<>());
            }
        }
        // 分页查询消息模板列表，并转换为消息模板基本信息DTO列表
        return R.ok(this.service.listPage(queryParam, templateIds).convertBatch(this::modelConvert));
    }

    /**
     * 获取所有消息模板
     *
     * @return 返回消息模板列表
     */
    @PostRequest(order = 4, value = "/info/list/all", summary = "获取所有消息模板", description = "获取所有消息模板")
    public R<List<MessageTemplateBasicDTO>> all() {
        // 调用服务层获取所有消息模板
        return R.ok(this.modelConvert(this.service.list()));
    }

    /**
     * 根据id查询消息模板详情
     *
     * @param id 消息模板id
     * @return 消息模板详情
     */
    @PostRequest(order = 5, value = "/detail/id", summary = "根据id查询消息模板详情", description = "根据id查询消息模板详情")
    public R<MessageTemplateDTO> detail(@RequestBody String id) {
        // 根据id查询消息模板实体
        MessageTemplateDO entity = this.service.getById(id);
        if (null == entity) {
            throw new FrameworkException(MessageExceptionInfo.MESSAGE_TEMPLATE_NOT_FOUND);
        }
        // 将消息模板实体转换为消息模板DTO
        MessageTemplateDTO result = Tools.Bean.copy(entity, MessageTemplateDTO.class);
        // 查询消息模板关联的消息通道定义列表
        List<MessageChannelDefinitionDO> channelDefinitionEntities = this.channelDefinitionService.listByTemplateId(id);
        List<MessageChannelDefinitionDTO> channelDefinitions;
        if (Tools.Coll.isNotBlank(channelDefinitionEntities)) {
            // 将消息通道定义列表转换为消息通道定义id列表
            List<String> channelDefinitionIds = Tools.Coll.convertList(channelDefinitionEntities, MessageChannelDefinitionDO::getId);
            // 查询消息通道定义关联的消息参数定义列表
            List<MessageParamDefinitionDO> paramDefinitionEntities = this.paramDefinitionService.listByChannelDefinitionIds(channelDefinitionIds);
            Map<String, List<MessageParamDefinitionDO>> paramDefinitionMap = Tools.Coll.convertGroup(paramDefinitionEntities, MessageParamDefinitionDO::getChannelDefinitionId);
            // 查询消息通道定义关联的消息重定向定义列表
            List<MessageRedirectDefinitionDO> redirectDefinitionEntities = this.redirectDefinitionService.listByChannelDefinitionIds(channelDefinitionIds);
            Map<String, List<MessageRedirectDefinitionDO>> redirectDefinitionMap = Tools.Coll.convertGroup(redirectDefinitionEntities, MessageRedirectDefinitionDO::getChannelDefinitionId);
            // 将消息通道定义列表转换为消息通道定义DTO列表
            channelDefinitions = Tools.Coll.convertList(channelDefinitionEntities, channelDefinitionEntity -> {
                MessageChannelDefinitionDTO channelDefinition = Tools.Bean.copy(channelDefinitionEntity, MessageChannelDefinitionDTO.class);
                channelDefinition.setConfigured(true);
                if (null != channelDefinition.getChannel()) {
                    channelDefinition.setChannelName(channelDefinition.getChannel().description);
                }
                channelDefinition.setStatusName(channelDefinition.getStatus().description);
                channelDefinition.setParamDefinitions(Tools.Coll.convertList(paramDefinitionMap.get(channelDefinitionEntity.getId()), paramDefinitionEntity -> Tools.Bean.copy(paramDefinitionEntity, MessageParamDefinitionDTO.class)));
                channelDefinition.setRedirectDefinitions(Tools.Coll.convertList(redirectDefinitionMap.get(channelDefinitionEntity.getId()), redirectDefinitionEntity -> Tools.Bean.copy(redirectDefinitionEntity, MessageRedirectDefinitionDTO.class)));
                return channelDefinition;
            });
            // 查询预览消息通道定义列表
            channelDefinitions.addAll(this.previewChannelDefinition(id, Tools.Coll.convertList(channelDefinitionEntities, channelDefinitionEntity -> MessageSendChannelEnum.valueOf(channelDefinitionEntity.getChannel()))));
        } else {
            // 查询预览消息通道定义列表
            channelDefinitions = this.previewChannelDefinition(id);
        }
        // 设置消息模板DTO的通道定义列表
        result.setChannelDefinitions(channelDefinitions);
        return R.ok(result);
    }

    /**
     * 获取业务类型列表
     *
     * @param queryParam 查询参数
     * @return 业务类型列表
     */
    @PostRequest(order = 6, value = "/business-type/list", summary = "获取业务类型列表", description = "获取业务类型列表")
    public R<List<MessageBusinessTypeDTO>> listBusinessType(@RequestBody MessageBusinessTypeQueryParamDTO queryParam) {
        // 获取业务类型和业务名称列表
        List<MessageTemplateDO> entities = this.service.listBusinessKeyAndBusinessName(queryParam.getBusinessName());
        // 根据业务类型分组
        Map<String, List<MessageTemplateDO>> templateMap = Tools.Coll.convertGroup(entities, MessageTemplateDO::getBusinessKey);
        List<MessageBusinessTypeDTO> result = new ArrayList<>();
        // 根据查询参数排除所有配置模板或非配置模板
        if (Boolean.TRUE.equals(queryParam.getExcludeAllTemplateConfigured())) {
            for (Map.Entry<String, List<MessageTemplateDO>> entry : templateMap.entrySet()) {
                if (Tools.Coll.contains(entry.getValue(), MessageTemplateDO::getConfigured, false)) {
                    MessageBusinessTypeDTO messageBusinessType = new MessageBusinessTypeDTO();
                    messageBusinessType.setBusinessKey(entry.getKey());
                    messageBusinessType.setBusinessName(entry.getValue().get(0).getBusinessName());
                    result.add(messageBusinessType);
                }
            }
        } else if (Boolean.TRUE.equals(queryParam.getExcludeNonTemplateConfigured())) {
            for (Map.Entry<String, List<MessageTemplateDO>> entry : templateMap.entrySet()) {
                if (Tools.Coll.contains(entry.getValue(), MessageTemplateDO::getConfigured, true)) {
                    MessageBusinessTypeDTO messageBusinessType = new MessageBusinessTypeDTO();
                    messageBusinessType.setBusinessKey(entry.getKey());
                    messageBusinessType.setBusinessName(entry.getValue().get(0).getBusinessName());
                    result.add(messageBusinessType);
                }
            }
        } else {
            // 获取所有业务类型和业务名称
            templateMap.forEach((businessKey, templateEntities) -> {
                MessageBusinessTypeDTO messageBusinessType = new MessageBusinessTypeDTO();
                messageBusinessType.setBusinessKey(businessKey);
                messageBusinessType.setBusinessName(templateEntities.get(0).getBusinessName());
                result.add(messageBusinessType);
            });
        }
        return R.ok(result);
    }

    /**
     * 根据业务标识查询消息模板
     *
     * @param businessKey 业务标识
     * @return 消息模板列表
     */
    @PostRequest(order = 7, value = "/info/list/business-key", summary = "根据业务标识查询消息模板", description = "根据业务标识查询消息模板")
    public R<List<MessageTemplateBasicDTO>> listInfoByBusinessKey(@Parameter(name = "businessKey", description = "业务标识")
                                                                  @RequestBody String businessKey) {
        // 查询未配置的业务模块消息模板
        List<MessageTemplateDO> entities = this.service.listNonConfiguredByBusinessKey(businessKey);
        // 将查询结果转换为消息模板并返回
        return R.ok(Tools.Coll.convertList(entities, entity -> Tools.Bean.copy(entity, MessageTemplateBasicDTO.class)));
    }

    /**
     * 添加消息渠道配置信息
     *
     * @param channelDefinition 消息渠道配置信息
     * @return 返回添加成功后的ID
     */
    @Transactional(rollbackFor = Exception.class)
    @PostRequest(order = 8, value = "/channel/definition/add", summary = "添加消息渠道配置信息", description = "添加消息渠道配置信息")
    public R<String> addChannelDefinition(@Parameter(name = "channelDefinition", description = "消息渠道配置信息")
                                          @RequestBody MessageChannelDefinitionDTO channelDefinition) {
        // 检查消息渠道是否已存在
        if (this.channelDefinitionService.channelExist(channelDefinition.getTemplateId(), channelDefinition.getChannel().name())) {
            throw new FrameworkException(MessageExceptionInfo.MESSAGE_CHANNEL_ALREADY_DEFINED);
        }
        // 获取消息模板实体
        MessageTemplateDO templateEntity = this.service.getByIdAndTenantCode(channelDefinition.getTemplateId(), Me.tenantCode());
        templateEntity.setConfigured(true);

        // 创建消息渠道配置实体
        MessageChannelDefinitionDO channelDefinitionEntity = Tools.Bean.copy(channelDefinition, MessageChannelDefinitionDO.class);
        channelDefinitionEntity.setId(Tools.Id.uuid());
        channelDefinitionEntity.setTemplateId(templateEntity.getId());
        channelDefinitionEntity.setTenantCode(Me.tenantCode());
        channelDefinitionEntity.setShowNotification(true);

        // 保存参数和重定向定义
        this.saveParamAndRedirectDefinition(templateEntity.getId(), channelDefinitionEntity.getId(), channelDefinition);
        // 保存消息渠道配置实体
        this.channelDefinitionService.save(channelDefinitionEntity);
        // 更新消息模板实体
        this.service.updateById(templateEntity);
        return R.ok(channelDefinitionEntity.getId());
    }

    /**
     * 更新消息渠道配置信息
     *
     * @param channelDefinition 消息渠道配置信息
     * @return 更新结果
     */
    @PostRequest(order = 9, value = "/channel/definition/update", summary = "更新消息渠道配置信息", description = "更新消息渠道配置信息")
    public R<Object> updateChannelDefinition(@Parameter(name = "channelDefinition", description = "消息渠道配置信息")
                                             @RequestBody MessageChannelDefinitionDTO channelDefinition) {
        // 检查消息渠道配置是否存在
        if (!this.channelDefinitionService.exist(channelDefinition.getId())) {
            throw new FrameworkException(MessageExceptionInfo.MESSAGE_CHANNEL_DEFINITION_NOT_FOUND);
        }
        // 将DTO转换为DO对象
        MessageChannelDefinitionDO entity = Tools.Bean.copy(channelDefinition, MessageChannelDefinitionDO.class);
        // 设置展示通知为true
        entity.setShowNotification(true);
        // 删除关联的参数定义和重定向定义
        this.paramDefinitionService.removeById(channelDefinition.getId());
        this.redirectDefinitionService.removeById(channelDefinition.getId());
        // 保存参数定义和重定向定义
        this.saveParamAndRedirectDefinition(channelDefinition.getTemplateId(), channelDefinition.getId(), channelDefinition);
        // 更新消息渠道配置信息
        this.channelDefinitionService.updateById(entity);
        return R.ok();
    }

    /**
     * 启用消息渠道定义
     *
     * @param channelDefinitionId 消息通道定义ID
     * @return 返回操作结果
     */
    @PostRequest(order = 10, value = "/channel/definition/enable", summary = "启用消息渠道定义", description = "启用消息渠道定义")
    public R<Object> enableChannelDefinition(@RequestBody String channelDefinitionId) {
        // 获取消息通道定义实体
        MessageChannelDefinitionDO channelDefinitionEntity = this.channelDefinitionService.getById(channelDefinitionId);
        // 如果消息通道定义ID为空，则抛出异常
        if (null == channelDefinitionId) {
            throw new FrameworkException(MessageExceptionInfo.MESSAGE_CHANNEL_DEFINITION_NOT_FOUND);
        }
        // 设置消息通道定义状态为启用
        channelDefinitionEntity.setStatus(MessageChannelStatusEnum.ENABLED.name());
        // 更新消息通道定义实体
        this.channelDefinitionService.updateById(channelDefinitionEntity);
        // 返回操作结果
        return R.ok();
    }

    /**
     * 禁用消息渠道定义
     *
     * @param channelDefinitionId 消息渠道定义ID
     * @return 返回操作结果
     */
    @PostRequest(order = 11, value = "/channel/definition/disable", summary = "禁用消息渠道定义", description = "禁用消息渠道定义")
    public R<Object> disableChannelDefinition(@RequestBody String channelDefinitionId) {
        // 根据消息通道定义ID获取消息通道定义实体
        MessageChannelDefinitionDO channelDefinitionEntity = this.channelDefinitionService.getById(channelDefinitionId);
        // 如果消息通道定义ID为空，则抛出异常
        if (null == channelDefinitionId) {
            throw new FrameworkException(MessageExceptionInfo.MESSAGE_CHANNEL_DEFINITION_NOT_FOUND);
        }
        // 设置消息通道定义状态为禁用
        channelDefinitionEntity.setStatus(MessageChannelStatusEnum.DISABLED.name());
        // 更新消息通道定义实体
        this.channelDefinitionService.updateById(channelDefinitionEntity);
        // 返回成功状态码
        return R.ok();
    }

    /**
     * 根据模板ID预览消息渠道定义
     *
     * @param templateId 编号
     * @return 预览结果
     */
    @PostRequest(order = 12, value = "/channel/definition/preview/template-id", summary = "根据模板ID预览消息渠道定义", description = "根据模板ID预览消息渠道定义")
    public R<List<MessageChannelDefinitionDTO>> previewChannelDefinitionByTemplateId(@Parameter(name = "templateId", description = "编号")
                                                                                     @RequestBody String templateId) {
        return R.ok(this.previewChannelDefinition(templateId));
    }

    /**
     * 预览渠道定义
     *
     * @param templateId 模板ID
     * @return 预览渠道定义列表
     */
    private List<MessageChannelDefinitionDTO> previewChannelDefinition(String templateId) {
        return this.previewChannelDefinition(templateId, new ArrayList<>());
    }


    /**
     * 预览渠道定义
     *
     * @param templateId        模板ID
     * @param configuredChannel 已配置的渠道
     * @return 预览渠道定义列表
     */
    private List<MessageChannelDefinitionDTO> previewChannelDefinition(String templateId, List<MessageSendChannelEnum> configuredChannel) {
        // 获取未配置的渠道
        List<MessageSendChannelEnum> nonConfiguredChannel = Tools.Array.filter(MessageSendChannelEnum.values(), sendChannel -> !configuredChannel.contains(sendChannel));
        if (Tools.Coll.isBlank(nonConfiguredChannel)) {
            return new ArrayList<>();
        }
        // 获取参数定义实体列表
        List<MessageParamDefinitionDO> paramDefinitionEntities = this.paramDefinitionService.listPreDefinitionByTemplateId(templateId);
        return Tools.Coll.convertList(nonConfiguredChannel, channel -> {
            // 创建渠道定义DTO
            MessageChannelDefinitionDTO channelDefinition = new MessageChannelDefinitionDTO();
            channelDefinition.setChannel(channel);
            channelDefinition.setChannelName(channel.description);
            channelDefinition.setStatus(MessageChannelStatusEnum.DISABLED);
            channelDefinition.setStatusName(MessageChannelStatusEnum.DISABLED.description);
            channelDefinition.setConfigured(false);
            channelDefinition.setParamDefinitions(Tools.Coll.convertList(paramDefinitionEntities, entity -> Tools.Bean.copy(entity, MessageParamDefinitionDTO.class)));
            return channelDefinition;
        });
    }


    /**
     * 获取参数定义列表
     *
     * @param id 编号
     * @return 参数定义列表
     */
    @PostRequest(order = 13, value = "/param/pre-definition/id", summary = "获取参数定义列表", description = "获取参数定义列表")
    public R<List<MessageParamDefinitionDTO>> listPreParamDefinitionById(@Parameter(name = "id", description = "编号")
                                                                         @RequestBody String id) {
        // 调用服务层方法获取预定义参数列表
        List<MessageParamDefinitionDO> entities = this.paramDefinitionService.listPreDefinitionByTemplateId(id);
        // 将实体列表转换为DTO列表并返回
        return R.ok(Tools.Coll.convertList(entities, entity -> Tools.Bean.copy(entity, MessageParamDefinitionDTO.class)));
    }

    /**
     * 消息模板定义信息上报
     *
     * @param reportParam 上报参数
     * @return 上报结果
     */
    @Override
    public R<Object> report(@RequestBody MessageTemplateBeanDefinitionReportParam reportParam) {
        // 调用服务层的report方法
        this.service.report(reportParam.getBeanDefinitions());
        // 返回报告结果
        return R.ok();
    }

    /**
     * 将实体对象转换为基本DTO对象
     *
     * @param entity         实体对象
     * @param channelNameMap channel名称映射表
     * @return 基本DTO对象
     */
    private MessageTemplateBasicDTO modelConvert(MessageTemplateDO entity, Map<String, List<String>> channelNameMap) {
        MessageTemplateBasicDTO template = Tools.Bean.copy(entity, MessageTemplateBasicDTO.class);
        if (channelNameMap.containsKey(entity.getId())) {
            template.setChannelNames(Tools.Coll.join(channelNameMap.get(entity.getId())));
        }
        return template;
    }


    /**
     * 将实体转换为DTO列表
     *
     * @param entities 实体列表
     * @return DTO列表
     */
    private List<MessageTemplateBasicDTO> modelConvert(List<MessageTemplateDO> entities) {
        // 根据实体列表获取通道定义实体列表
        List<MessageChannelDefinitionDO> channelDefinitionEntities = this.channelDefinitionService.listByTemplateIds(Tools.Coll.convertList(entities, MessageTemplateDO::getId));
        // 将通道定义实体列表转换为通道名称的映射表
        Map<String, List<String>> channelNameMap = Tools.Coll.convertGroup(channelDefinitionEntities, MessageChannelDefinitionDO::getTemplateId, entity -> MessageSendChannelEnum.valueOf(entity.getChannel()).description);
        // 根据实体列表和通道名称的映射表，将每个实体转换为DTO
        return Tools.Coll.convertList(entities, entity -> this.modelConvert(entity, channelNameMap));
    }


    /**
     * 保存参数和重定向定义，并重定向到定义页面
     *
     * @param templateId          模板ID
     * @param channelDefinitionId 通道定义ID
     * @param channelDefinition   通道定义
     */
    private void saveParamAndRedirectDefinition(String templateId, String channelDefinitionId, MessageChannelDefinitionDTO channelDefinition) {
        // 如果通道定义中存在参数定义，则保存参数定义
        if (Tools.Coll.isNotBlank(channelDefinition.getParamDefinitions())) {
            this.paramDefinitionService.saveBatch(Tools.Coll.convertList(channelDefinition.getParamDefinitions(), paramDefinition -> {
                // 创建参数定义实体
                MessageParamDefinitionDO entity = Tools.Bean.copy(paramDefinition, MessageParamDefinitionDO.class);
                entity.setId(Tools.Id.uuid());
                entity.setTemplateId(templateId);
                entity.setChannelDefinitionId(channelDefinitionId);
                entity.setPreDefinition(false);
                entity.setTenantCode(Me.tenantCode());
                return entity;
            }));
        }

        // 如果通道定义中存在重定向定义，则保存重定向定义
        if (Tools.Coll.isNotBlank(channelDefinition.getRedirectDefinitions())) {
            this.redirectDefinitionService.saveBatch(Tools.Coll.convertList(channelDefinition.getRedirectDefinitions(), redirectDefinition -> {
                // 创建重定向定义实体
                MessageRedirectDefinitionDO entity = Tools.Bean.copy(redirectDefinition, MessageRedirectDefinitionDO.class);
                entity.setId(Tools.Id.uuid());
                entity.setTemplateId(templateId);
                entity.setChannelDefinitionId(channelDefinitionId);
                entity.setTenantCode(Me.tenantCode());
                return entity;
            }));
        }
    }
}
